
#include "stdafx.h"
#include "pluginprotocol.h"
#include "snburl.h"
#include "data\booklibrary.h"
#include "utils\snb\datareader.h"
#include "plugin\htmlplugin\htmlplugin_i.h"


// CPluginProtocol
// IUnknown
STDMETHODIMP CPluginProtocol::QueryInterface(REFIID riid, void** ppvObject)
{
	if (ppvObject == NULL)
		return E_INVALIDARG;

	*ppvObject = NULL;

	if (IID_IUnknown == riid)
		*ppvObject = (IInternetProtocol *)(this);
	else if (IID_IInternetProtocol == riid || IID_IInternetProtocolRoot == riid)
		*ppvObject = (IInternetProtocol *)(this);
	else if (IID_IInternetProtocolInfo == riid)
		*ppvObject  = (IInternetProtocolInfo *)(this);

	if (*ppvObject != NULL)
	{
		((LPUNKNOWN)*ppvObject)->AddRef();
		return S_OK;
	}

	return E_NOINTERFACE;
}

STDMETHODIMP_(ULONG) CPluginProtocol::AddRef()
{
	return ++m_cRef;
}

STDMETHODIMP_(ULONG) CPluginProtocol::Release()
{
	long nTemp = --m_cRef;
	if (nTemp == 0)
		delete this;

	return nTemp;
}

// IInternetProtocolRoot
STDMETHODIMP CPluginProtocol::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved)
{
	m_nCurPos = 0;
	m_nDataBufferLen = 0;

	if (pOIProtSink == NULL)
		return E_POINTER;

	const wchar_t szPattern[] = L"^(plugin://)([^/]+)[/]+(.*)";
	boost::xpressive::wcregex rex = boost::xpressive::wcregex::compile(szPattern, boost::xpressive::icase);
	boost::xpressive::wcmatch urlparts;
	if (!boost::xpressive::regex_match(szUrl, urlparts, rex))
		return INET_E_INVALID_REQUEST;

	std::wstring strClsid = urlparts[2];
	std::wstring strGetImage = urlparts[3];

	CLSID clsid;
	if (FAILED(CLSIDFromString((LPOLESTR)strClsid.c_str(), &clsid)))
		return INET_E_INVALID_REQUEST;

	if (!boost::algorithm::iequals(strGetImage, L"getimage"))
		return INET_E_INVALID_REQUEST;

	CComPtr<IConvertPlugin> spConvertPlugin;
	if (FAILED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(IConvertPlugin), (LPVOID*)&spConvertPlugin)))
		return INET_E_INVALID_REQUEST;

	CComVariant varImage;
	if (FAILED(spConvertPlugin->GetImage(&varImage)))
		return INET_E_DATA_NOT_AVAILABLE;

	m_nDataBufferLen = SysStringByteLen(varImage.bstrVal);
	if (m_nDataBufferLen == 0)
		return INET_E_DATA_NOT_AVAILABLE;

	m_pDataBuffer.Reallocate(m_nDataBufferLen);
	memcpy_s(m_pDataBuffer, m_nDataBufferLen, varImage.bstrVal, m_nDataBufferLen);

	pOIProtSink->ReportProgress(BINDSTATUS_FINDINGRESOURCE, NULL);
	pOIProtSink->ReportProgress(BINDSTATUS_CONNECTING, NULL);
	pOIProtSink->ReportProgress(BINDSTATUS_SENDINGREQUEST, NULL);
	pOIProtSink->ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, L"image/png");
	pOIProtSink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0, m_nDataBufferLen);
	pOIProtSink->ReportData(BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, m_nDataBufferLen, m_nDataBufferLen);

	return S_OK;
}

STDMETHODIMP CPluginProtocol::Continue(PROTOCOLDATA *pProtocolData)
{	
	return S_OK;
}

STDMETHODIMP CPluginProtocol::Abort(HRESULT hrReason, DWORD dwOptions)
{
	return S_OK;
}

STDMETHODIMP CPluginProtocol::Terminate(DWORD dwOptions)
{
	return S_OK;
}

STDMETHODIMP CPluginProtocol::Suspend()
{
	return E_NOTIMPL;
}

STDMETHODIMP CPluginProtocol::Resume()
{
	return E_NOTIMPL;
}

// IInternetProtocol
STDMETHODIMP CPluginProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
{
	HRESULT hr = S_OK;

	if (m_nCurPos >= m_nDataBufferLen)
		return S_FALSE;

	LPBYTE pbData = m_pDataBuffer + m_nCurPos;
	DWORD cbAvail = m_nDataBufferLen - m_nCurPos;

	if (cbAvail > cb)
	{
		memcpy_s(pv, cb, pbData, cb);

		m_nCurPos += cb;
		*pcbRead = cb;
	}
	else
	{
		memcpy_s(pv, cb, pbData, cbAvail);

		m_nCurPos += cbAvail;
		*pcbRead = cbAvail;
	}

	return S_OK;
}

STDMETHODIMP CPluginProtocol::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
{
	return E_NOTIMPL;;
}

STDMETHODIMP CPluginProtocol::LockRequest(DWORD dwOptions)
{
	return S_OK;
}

STDMETHODIMP CPluginProtocol::UnlockRequest()
{
	return S_OK;
}

// IInternetProtocolInfo
STDMETHODIMP CPluginProtocol::ParseUrl(LPCWSTR pwzUrl, PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
{
	return INET_E_DEFAULT_ACTION;
}

STDMETHODIMP CPluginProtocol::CombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
{
	return INET_E_DEFAULT_ACTION;
}

STDMETHODIMP CPluginProtocol::CompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags)
{
	if (pwzUrl1 == NULL || pwzUrl2 == NULL)
		return E_POINTER;

	HRESULT hr = S_FALSE;
	if (_wcsicmp(pwzUrl1, pwzUrl2) == 0)
		return S_OK;
	else
		return S_FALSE;
}

STDMETHODIMP CPluginProtocol::QueryInfo(LPCWSTR pwzUrl, QUERYOPTION OueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD *pcbBuf, DWORD dwReserved)
{
	return INET_E_DEFAULT_ACTION;
}

//////////////////////////////////////////////////////////////////////////
// CPluginProtocolCF

// IUnknown
STDMETHODIMP CPluginProtocolCF::QueryInterface(REFIID riid, void** ppvObject)
{
	if (ppvObject == NULL)
		return E_INVALIDARG;

	*ppvObject = NULL;

	if (IID_IUnknown == riid || IID_IClassFactory == riid)
		*ppvObject = (IClassFactory *)(this);

	if (*ppvObject != NULL)
	{
		((LPUNKNOWN)*ppvObject)->AddRef();
		return S_OK;
	}

	return E_NOINTERFACE;
}

STDMETHODIMP_(ULONG) CPluginProtocolCF::AddRef()
{
	return ++m_cRef;
}

STDMETHODIMP_(ULONG) CPluginProtocolCF::Release()
{
	long nTemp = --m_cRef;
	if (nTemp == 0)
		delete this;

	return nTemp;
}

// IClassFactory
STDMETHODIMP CPluginProtocolCF::CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppvObject)
{
	if (ppvObject == NULL)
		return E_INVALIDARG;

	*ppvObject = NULL;

	if (pUnkOuter != NULL)
		return CLASS_E_NOAGGREGATION;

	CPluginProtocol* pSnbfileProtocol = new CPluginProtocol();
	return pSnbfileProtocol->QueryInterface(riid, ppvObject);
}

STDMETHODIMP CPluginProtocolCF::LockServer(BOOL fLock)
{
	return S_OK;
}

